home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / djgpp / libsrc / c / io / doprnt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-04  |  20.8 KB  |  858 lines

  1. /* This is file DOPRNT.C */
  2. /* This file may have been modified by DJ Delorie (Jan 1991).  If so,
  3. ** these modifications are Coyright (C) 1993 DJ Delorie, 24 Kirsten Ave,
  4. ** Rochester NH, 03867-2954, USA.
  5. */
  6.  
  7. /*
  8.  * Copyright (c) 1988 Regents of the University of California.
  9.  * All rights reserved.
  10.  *
  11.  * Redistribution and use in source and binary forms are permitted provided
  12.  * that: (1) source distributions retain this entire copyright notice and
  13.  * comment, and (2) distributions including binaries display the following
  14.  * acknowledgement:  ``This product includes software developed by the
  15.  * University of California, Berkeley and its contributors'' in the
  16.  * documentation or other materials provided with the distribution and in
  17.  * all advertising materials mentioning features or use of this software.
  18.  * Neither the name of the University nor the names of its contributors may
  19.  * be used to endorse or promote products derived from this software without
  20.  * specific prior written permission.
  21.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  22.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  23.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  24.  */
  25.  
  26. #if defined(LIBC_SCCS) && !defined(lint)
  27. static char sccsid[] = "@(#)doprnt.c    5.39 (Berkeley) 6/28/90";
  28. #endif /* LIBC_SCCS and not lint */
  29.  
  30. #define _doprnt ____doprnt
  31. #include <sys/types.h>
  32. #include <varargs.h>
  33. #include <stdio.h>
  34. #include <ctype.h>
  35. #include <locale.h>
  36. #include <stdlib.h>
  37. #include <string.h>
  38. #undef _doprnt
  39.  
  40. static char decimal = '.';
  41.  
  42. /* 11-bit exponent (VAX G floating point) is 308 decimal digits */
  43. #define    MAXEXP        308
  44. #define MAXEXPLD        4952 /* this includes subnormal numbers */
  45. /* 128 bit fraction takes up 39 decimal digits; max reasonable precision */
  46. #define    MAXFRACT    39
  47.  
  48. #define    DEFPREC        6
  49. #define    DEFLPREC    14
  50.  
  51. #define    BUF        (MAXEXPLD+MAXFRACT+1)    /* + decimal point */
  52.  
  53. #define    PUTC(ch)    (void) putc(ch, fp)
  54.  
  55. #define ARG(basetype) \
  56.     _ulong = flags&LONGINT ? va_arg(argp, long basetype) : \
  57.         flags&SHORTINT ? (short basetype)va_arg(argp, int) : \
  58.         va_arg(argp, int)
  59.  
  60. static int nan = 0;
  61.  
  62. #if 0
  63. #define    todigit(c)    ((c) - '0')
  64. #define    tochar(n)    ((n) + '0')
  65. #else
  66. static int todigit(char c)
  67. {
  68.   if (c<='0') return 0;
  69.   if (c>='9') return 9;
  70.   return c-'0';
  71. }
  72. static char tochar(int n)
  73. {
  74.   if (n>=9) return '9';
  75.   if (n<=0) return '0';
  76.   return n+'0';
  77. }
  78. #endif
  79.  
  80. /* have to deal with the negative buffer count kludge */
  81. #define    NEGATIVE_COUNT_KLUDGE
  82.  
  83. #define    LONGINT        0x01        /* long integer */
  84. #define    LONGDBL        0x02        /* long double */
  85. #define    SHORTINT    0x04        /* short integer */
  86. #define    ALT        0x08        /* alternate form */
  87. #define    LADJUST        0x10        /* left adjustment */
  88. #define    ZEROPAD        0x20        /* zero (as opposed to blank) pad */
  89. #define    HEXPREFIX    0x40        /* add 0x or 0X prefix */
  90.  
  91. static cvtl(long double number, int prec, int flags, char *signp,
  92.         u_char fmtch, char *startp, char *endp);
  93. static char *roundl(long double fract, int *exp, char *start, char *end,
  94.             char ch, char *signp);
  95. static char *exponentl(char *p, int exp, u_char fmtch);
  96. #ifdef __GO32__
  97. static int isspeciall(long double d, char *bufp);
  98. #endif
  99.  
  100. /* don't want to include <math.h> */
  101. long double modfl(long double, long double *);
  102. long double scalbl(long double, int);
  103.  
  104. int
  105. _doprnt(fmt0, argp, fp)
  106.     const char *fmt0;
  107.     va_list argp;
  108.     FILE *fp;
  109. {
  110.     const char *fmt;    /* format string */
  111.     int ch;            /* character from fmt */
  112.     int cnt;        /* return value accumulator */
  113.     int n;            /* random handy integer */
  114.     char *t;        /* buffer pointer */
  115.     long double _ldouble;    /* double and long double precision arguments
  116.                    %L.[eEfgG] */
  117.     u_long _ulong;        /* integer arguments %[diouxX] */
  118.     int base;        /* base for [diouxX] conversion */
  119.     int dprec;        /* decimal precision in [diouxX] */
  120.     int fieldsz;        /* field size expanded by sign, etc */
  121.     int flags;        /* flags as above */
  122.     int fpprec;        /* `extra' floating precision in [eEfgG] */
  123.     int prec;        /* precision from format (%.3d), or -1 */
  124.     int realsz;        /* field size expanded by decimal precision */
  125.     int size;        /* size of converted field or string */
  126.     int width;        /* width from format (%8d), or 0 */
  127.     char sign;        /* sign prefix (' ', '+', '-', or \0) */
  128.     char softsign;        /* temporary negative sign for floats */
  129.     char *digs;        /* digits for [diouxX] conversion */
  130.     char buf[BUF];        /* space for %c, %[diouxX], %[eEfgG] */
  131.  
  132.     decimal = localeconv()->decimal_point[0];
  133.  
  134.     if (fp->_flag & _IORW) {
  135.         fp->_flag |= _IOWRT;
  136.         fp->_flag &= ~(_IOEOF|_IOREAD);
  137.     }
  138.     if ((fp->_flag & _IOWRT) == 0)
  139.         return (EOF);
  140.  
  141.     fmt = fmt0;
  142.     digs = "0123456789abcdef";
  143.     for (cnt = 0;; ++fmt) {
  144.         n = fp->_cnt;
  145.         for (t = (char *)fp->_ptr; (ch = *fmt) && ch != '%';
  146.              ++cnt, ++fmt)
  147.             if (--n < 0
  148. #ifdef NEGATIVE_COUNT_KLUDGE
  149.                 && (!(fp->_flag & _IOLBF) || -n >= fp->_bufsiz)
  150. #endif
  151.                 || (ch == '\n' && fp->_flag & _IOLBF)) {
  152.                 fp->_cnt = n;
  153.                 fp->_ptr = t;
  154.                 (void) _flsbuf((u_char)ch, fp);
  155.                 n = fp->_cnt;
  156.                 t = (char *)fp->_ptr;
  157.             } else
  158.                 *t++ = ch;
  159.         fp->_cnt = n;
  160.         fp->_ptr = t;
  161.         if (!ch)
  162.             return (cnt);
  163.         flags = 0; dprec = 0; fpprec = 0; width = 0;
  164.         prec = -1;
  165.         sign = '\0';
  166. rflag:        switch (*++fmt) {
  167.         case ' ':
  168.             /*
  169.              * ``If the space and + flags both appear, the space
  170.              * flag will be ignored.''
  171.              *    -- ANSI X3J11
  172.              */
  173.             if (!sign)
  174.                 sign = ' ';
  175.             goto rflag;
  176.         case '#':
  177.             flags |= ALT;
  178.             goto rflag;
  179.         case '*':
  180.             /*
  181.              * ``A negative field width argument is taken as a
  182.              * - flag followed by a  positive field width.''
  183.              *    -- ANSI X3J11
  184.              * They don't exclude field widths read from args.
  185.              */
  186.             if ((width = va_arg(argp, int)) >= 0)
  187.                 goto rflag;
  188.             width = -width;
  189.             /* FALLTHROUGH */
  190.         case '-':
  191.             flags |= LADJUST;
  192.             goto rflag;
  193.         case '+':
  194.             sign = '+';
  195.             goto rflag;
  196.         case '.':
  197.             if (*++fmt == '*')
  198.                 n = va_arg(argp, int);
  199.             else {
  200.                 n = 0;
  201.                 while (isascii(*fmt) && isdigit(*fmt))
  202.                     n = 10 * n + todigit(*fmt++);
  203.                 --fmt;
  204.             }
  205.             prec = n < 0 ? -1 : n;
  206.             goto rflag;
  207.         case '0':
  208.             /*
  209.              * ``Note that 0 is taken as a flag, not as the
  210.              * beginning of a field width.''
  211.              *    -- ANSI X3J11
  212.              */
  213.             flags |= ZEROPAD;
  214.             goto rflag;
  215.         case '1': case '2': case '3': case '4':
  216.         case '5': case '6': case '7': case '8': case '9':
  217.             n = 0;
  218.             do {
  219.                 n = 10 * n + todigit(*fmt);
  220.             } while (isascii(*++fmt) && isdigit(*fmt));
  221.             width = n;
  222.             --fmt;
  223.             goto rflag;
  224.         case 'L':
  225.             flags |= LONGDBL;
  226.             goto rflag;
  227.         case 'h':
  228.             flags |= SHORTINT;
  229.             goto rflag;
  230.         case 'l':
  231.             flags |= LONGINT;
  232.             goto rflag;
  233.         case 'c':
  234.             *(t = buf) = va_arg(argp, int);
  235.             size = 1;
  236.             sign = '\0';
  237.             goto pforw;
  238.         case 'D':
  239.             flags |= LONGINT;
  240.             /*FALLTHROUGH*/
  241.         case 'd':
  242.         case 'i':
  243.             ARG(int);
  244.             if ((long)_ulong < 0) {
  245.                 _ulong = -_ulong;
  246.                 sign = '-';
  247.             }
  248.             base = 10;
  249.             goto number;
  250.         case 'e':
  251.         case 'E':
  252.         case 'f':
  253.         case 'g':
  254.         case 'G':
  255.             if (flags & LONGDBL)
  256.                 _ldouble = va_arg(argp, long double);
  257.             else
  258.                 _ldouble = (long double)va_arg(argp, double);
  259.             /*
  260.              * don't do unrealistic precision; just pad it with
  261.              * zeroes later, so buffer size stays rational.
  262.              */
  263.             if (prec > MAXFRACT) {
  264.                 if (*fmt != 'g' && (*fmt != 'G' || (flags&ALT)))
  265.                     fpprec = prec - MAXFRACT;
  266.                 prec = MAXFRACT;
  267.             }
  268.             else if (prec == -1)
  269.             {
  270.                 if (flags&LONGINT)
  271.                     prec = DEFLPREC;
  272.                 else
  273.                     prec = DEFPREC;
  274.             }
  275.             /*
  276.              * softsign avoids negative 0 if _double is < 0 and
  277.              * no significant digits will be shown
  278.              */
  279.             if (_ldouble < 0) {
  280.                 softsign = '-';
  281.                 _ldouble = -_ldouble;
  282.             }
  283.             else
  284.                 softsign = 0;
  285.             /*
  286.              * cvt may have to round up past the "start" of the
  287.              * buffer, i.e. ``intf("%.2f", (double)9.999);'';
  288.              * if the first char isn't NULL, it did.
  289.              */
  290.             *buf = NULL;
  291.             size = cvtl(_ldouble, prec, flags, &softsign, *fmt, buf,
  292.                 buf + sizeof(buf));
  293.             if (softsign && !nan)
  294.                 sign = '-';
  295.             nan = 0;
  296.             t = *buf ? buf : buf + 1;
  297.             goto pforw;
  298.         case 'n':
  299.             if (flags & LONGINT)
  300.                 *va_arg(argp, long *) = cnt;
  301.             else if (flags & SHORTINT)
  302.                 *va_arg(argp, short *) = cnt;
  303.             else
  304.                 *va_arg(argp, int *) = cnt;
  305.             break;
  306.         case 'O':
  307.             flags |= LONGINT;
  308.             /*FALLTHROUGH*/
  309.         case 'o':
  310.             ARG(unsigned);
  311.             base = 8;
  312.             goto nosign;
  313.         case 'p':
  314.             /*
  315.              * ``The argument shall be a pointer to void.  The
  316.              * value of the pointer is converted to a sequence
  317.              * of printable characters, in an implementation-
  318.              * defined manner.''
  319.              *    -- ANSI X3J11
  320.              */
  321.             /* NOSTRICT */
  322.             _ulong = (u_long)va_arg(argp, void *);
  323.             base = 16;
  324.             goto nosign;
  325.         case 's':
  326.             if (!(t = va_arg(argp, char *)))
  327.                 t = "(null)";
  328.             if (prec >= 0) {
  329.                 /*
  330.                  * can't use strlen; can only look for the
  331.                  * NUL in the first `prec' characters, and
  332.                  * strlen() will go further.
  333.                  */
  334.                 char *p/*, *memchr() */;
  335.  
  336.                 if ((p = memchr(t, 0, prec))) {
  337.                     size = p - t;
  338.                     if (size > prec)
  339.                         size = prec;
  340.                 } else
  341.                     size = prec;
  342.             } else
  343.                 size = strlen(t);
  344.             sign = '\0';
  345.             goto pforw;
  346.         case 'U':
  347.             flags |= LONGINT;
  348.             /*FALLTHROUGH*/
  349.         case 'u':
  350.             ARG(unsigned);
  351.             base = 10;
  352.             goto nosign;
  353.         case 'X':
  354.             digs = "0123456789ABCDEF";
  355.             /* FALLTHROUGH */
  356.         case 'x':
  357.             ARG(unsigned);
  358.             base = 16;
  359.             /* leading 0x/X only if non-zero */
  360.             if (flags & ALT && _ulong != 0)
  361.                 flags |= HEXPREFIX;
  362.  
  363.             /* unsigned conversions */
  364. nosign:            sign = '\0';
  365.             /*
  366.              * ``... diouXx conversions ... if a precision is
  367.              * specified, the 0 flag will be ignored.''
  368.              *    -- ANSI X3J11
  369.              */
  370. number:            if ((dprec = prec) >= 0)
  371.                 flags &= ~ZEROPAD;
  372.  
  373.             /*
  374.              * ``The result of converting a zero value with an
  375.              * explicit precision of zero is no characters.''
  376.              *    -- ANSI X3J11
  377.              */
  378.             t = buf + BUF;
  379.             if (_ulong != 0 || prec != 0) {
  380.                 do {
  381.                     *--t = digs[_ulong % base];
  382.                     _ulong /= base;
  383.                 } while (_ulong);
  384.                 digs = "0123456789abcdef";
  385.                 if (flags & ALT && base == 8 && *t != '0')
  386.                     *--t = '0'; /* octal leading 0 */
  387.             }
  388.             size = buf + BUF - t;
  389.  
  390. pforw:
  391.             /*
  392.              * All reasonable formats wind up here.  At this point,
  393.              * `t' points to a string which (if not flags&LADJUST)
  394.              * should be padded out to `width' places.  If
  395.              * flags&ZEROPAD, it should first be prefixed by any
  396.              * sign or other prefix; otherwise, it should be blank
  397.              * padded before the prefix is emitted.  After any
  398.              * left-hand padding and prefixing, emit zeroes
  399.              * required by a decimal [diouxX] precision, then print
  400.              * the string proper, then emit zeroes required by any
  401.              * leftover floating precision; finally, if LADJUST,
  402.              * pad with blanks.
  403.              */
  404.  
  405.             /*
  406.              * compute actual size, so we know how much to pad
  407.              * fieldsz excludes decimal prec; realsz includes it
  408.              */
  409.             fieldsz = size + fpprec;
  410.             realsz = dprec > fieldsz ? dprec : fieldsz;
  411.             if (sign)
  412.                 realsz++;
  413.             if (flags & HEXPREFIX)
  414.                 realsz += 2;
  415.  
  416.             /* right-adjusting blank padding */
  417.             if ((flags & (LADJUST|ZEROPAD)) == 0 && width)
  418.                 for (n = realsz; n < width; n++)
  419.                     PUTC(' ');
  420.             /* prefix */
  421.             if (sign)
  422.                 PUTC(sign);
  423.             if (flags & HEXPREFIX) {
  424.                 PUTC('0');
  425.                 PUTC((char)*fmt);
  426.             }
  427.             /* right-adjusting zero padding */
  428.             if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
  429.                 for (n = realsz; n < width; n++)
  430.                     PUTC('0');
  431.             /* leading zeroes from decimal precision */
  432.             for (n = fieldsz; n < dprec; n++)
  433.                 PUTC('0');
  434.  
  435.             /* the string or number proper */
  436.             n = size;
  437.             if (fp->_cnt - n >= 0 && (fp->_flag & _IOLBF) == 0) {
  438.                 fp->_cnt -= n;
  439.                 bcopy(t, (char *)fp->_ptr, n);
  440.                 fp->_ptr += n;
  441.             } else
  442.                 while (--n >= 0)
  443.                     PUTC(*t++);
  444.             /* trailing f.p. zeroes */
  445.             while (--fpprec >= 0)
  446.                 PUTC('0');
  447.             /* left-adjusting padding (always blank) */
  448.             if (flags & LADJUST)
  449.                 for (n = realsz; n < width; n++)
  450.                     PUTC(' ');
  451.             /* finally, adjust cnt */
  452.             cnt += width > realsz ? width : realsz;
  453.             break;
  454.         case '\0':    /* "%?" prints ?, unless ? is NULL */
  455.             return (cnt);
  456.         default:
  457.             PUTC((char)*fmt);
  458.             cnt++;
  459.         }
  460.     }
  461.     /* NOTREACHED */
  462. }
  463.  
  464. static long double pten[] =
  465. {
  466.     1e1L, 1e2L, 1e4L, 1e8L, 1e16L, 1e32L, 1e64L, 1e128L, 1e256L,
  467.     1e512L, 1e1024L, 1e2048L, 1e4096L
  468. };
  469.  
  470. static long double ptenneg[] =
  471. {
  472.     1e-1L, 1e-2L, 1e-4L, 1e-8L, 1e-16L, 1e-32L, 1e-64L, 1e-128L, 1e-256L,
  473.     1e-512L, 1e-1024L, 1e-2048L, 1e-4096L
  474. };
  475.  
  476. #define MAXP 4096
  477. #define NP   12
  478. #define P    (4294967296.0L * 4294967296.0L * 2.0L)   /* 2^65 */
  479. static long double INVPREC = P;
  480. static long double PREC = 1.0L/P;
  481. #undef P
  482. /*
  483.  * Defining FAST_LDOUBLE_CONVERSION results in a little bit faster
  484.  * version, which might be less accurate (about 1 bit) for long
  485.  * double. For 'normal' double it doesn't matter.
  486.  */
  487. /* #define FAST_LDOUBLE_CONVERSION */
  488.  
  489. static int
  490. cvtl(long double number, int prec, int flags, char *signp, u_char fmtch,
  491.      char *startp, char *endp)
  492. {
  493.     register char *p, *t;
  494.     long double fract;
  495.     int dotrim, expcnt, gformat;
  496.     long double integer, tmp;
  497.  
  498. #ifdef __GO32__
  499.     if ((expcnt = isspeciall(number, startp)))
  500.         return(expcnt);
  501. #endif
  502.  
  503.     dotrim = expcnt = gformat = 0;
  504.     /* fract = modfl(number, &integer); */
  505.     integer = number;
  506.  
  507.     /* get an extra slot for rounding. */
  508.     t = ++startp;
  509.  
  510.     p = endp - 1;
  511.     if (integer) {
  512.         int i, lp=NP, pt=MAXP;
  513. #ifndef FAST_LDOUBLE_CONVERSION
  514.         long double oint = integer, dd=1.0L;
  515. #endif
  516.         if (integer > INVPREC) {
  517.             integer *= PREC;
  518.             while(lp >= 0) {
  519.                 if (integer >= pten[lp]) {
  520.                     expcnt += pt;
  521.                     integer *= ptenneg[lp];
  522. #ifndef FAST_LDOUBLE_CONVERSION
  523.                     dd *= pten[lp];
  524. #endif
  525.                 }
  526.                 pt >>= 1;
  527.                 lp--;
  528.             }
  529. #ifndef FAST_LDOUBLE_CONVERSION
  530.             integer = oint/dd;
  531. #else
  532.             integer *= INVPREC;
  533. #endif
  534.         }
  535.         /*
  536.          * Do we really need this ?
  537.          */
  538.         for (i = 0; i < expcnt; i++)
  539.             *p-- = '0';
  540.     }
  541.     number = integer;
  542.     fract = modfl(number, &integer);
  543.     /*
  544.      * get integer portion of number; put into the end of the buffer; the
  545.      * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
  546.      */
  547.     for (; integer; ++expcnt) {
  548.         tmp = modfl(integer * 0.1L , &integer);
  549.         *p-- = tochar((int)((tmp + .01L) * 10));
  550.     }
  551.     switch(fmtch) {
  552.     case 'f':
  553.         /* reverse integer into beginning of buffer */
  554.         if (expcnt)
  555.             for (; ++p < endp; *t++ = *p);
  556.         else
  557.             *t++ = '0';
  558.         /*
  559.          * if precision required or alternate flag set, add in a
  560.          * decimal point.
  561.          */
  562.         if (prec || flags&ALT)
  563.             *t++ = decimal;
  564.         /* if requires more precision and some fraction left */
  565.         if (fract) {
  566.             if (prec)
  567.                 do {
  568.                     fract = modfl(fract * 10.0L, &tmp);
  569.                     *t++ = tochar((int)tmp);
  570.                 } while (--prec && fract);
  571.             if (fract)
  572.                 startp = roundl(fract, (int *)NULL, startp,
  573.                     t - 1, (char)0, signp);
  574.         }
  575.         for (; prec--; *t++ = '0');
  576.         break;
  577.     case 'e':
  578.     case 'E':
  579. eformat:    if (expcnt) {
  580.             *t++ = *++p;
  581.             if (prec || flags&ALT)
  582.                 *t++ = decimal;
  583.             /* if requires more precision and some integer left */
  584.             for (; prec && ++p < endp; --prec)
  585.                 *t++ = *p;
  586.             /*
  587.              * if done precision and more of the integer component,
  588.              * round using it; adjust fract so we don't re-round
  589.              * later.
  590.              */
  591.             if (!prec && ++p < endp) {
  592.                 fract = 0;
  593.                 startp = roundl((long double)0.0L, &expcnt,
  594.                         startp, t - 1, *p, signp);
  595.             }
  596.             /* adjust expcnt for digit in front of decimal */
  597.             --expcnt;
  598.         }
  599.         /* until first fractional digit, decrement exponent */
  600.         else if (fract) {
  601.             int lp=NP, pt=MAXP;
  602. #ifndef FAST_LDOUBLE_CONVERSION
  603.             long double ofract = fract, dd=1.0L;
  604. #endif
  605.             expcnt = -1;
  606.             if (fract < PREC) {
  607.                 fract *= INVPREC;
  608.                 while(lp >= 0) {
  609.                     if (fract <= ptenneg[lp]) {
  610.                         expcnt -= pt;
  611.                         fract *= pten[lp];
  612. #ifndef FAST_LDOUBLE_CONVERSION
  613.                         dd *= pten[lp];
  614. #endif
  615.                     }
  616.                     pt >>= 1;
  617.                     lp--;
  618.                 }
  619. #ifndef FAST_LDOUBLE_CONVERSION
  620.                 fract = ofract*dd;
  621. #else
  622.                 fract *= PREC;
  623. #endif
  624.             }
  625.             /* adjust expcnt for digit in front of decimal */
  626.             for (/* expcnt = -1 */ ;; --expcnt) {
  627.                 fract = modfl(fract * 10.0L, &tmp);
  628.                 if (tmp)
  629.                     break;
  630.             }
  631.             *t++ = tochar((int)tmp);
  632.             if (prec || flags&ALT)
  633.                 *t++ = decimal;
  634.         }
  635.         else {
  636.             *t++ = '0';
  637.             if (prec || flags&ALT)
  638.                 *t++ = decimal;
  639.         }
  640.         /* if requires more precision and some fraction left */
  641.         if (fract) {
  642.             if (prec)
  643.                 do {
  644.                     fract = modfl(fract * 10.0L, &tmp);
  645.                     *t++ = tochar((int)tmp);
  646.                 } while (--prec && fract);
  647.             if (fract)
  648.                 startp = roundl(fract, &expcnt, startp,
  649.                     t - 1, (char)0, signp);
  650.         }
  651.         /* if requires more precision */
  652.         for (; prec--; *t++ = '0');
  653.  
  654.         /* unless alternate flag, trim any g/G format trailing 0's */
  655.         if (gformat && !(flags&ALT)) {
  656.             while (t > startp && *--t == '0');
  657.             if (*t == decimal)
  658.                 --t;
  659.             ++t;
  660.         }
  661.         t = exponentl(t, expcnt, fmtch);
  662.         break;
  663.     case 'g':
  664.     case 'G':
  665.         /* a precision of 0 is treated as a precision of 1. */
  666.         if (!prec)
  667.             ++prec;
  668.         /*
  669.          * ``The style used depends on the value converted; style e
  670.          * will be used only if the exponent resulting from the
  671.          * conversion is less than -4 or greater than the precision.''
  672.          *    -- ANSI X3J11
  673.          */
  674.         if (expcnt > prec || (!expcnt && fract && fract < .0001)) {
  675.             /*
  676.              * g/G format counts "significant digits, not digits of
  677.              * precision; for the e/E format, this just causes an
  678.              * off-by-one problem, i.e. g/G considers the digit
  679.              * before the decimal point significant and e/E doesn't
  680.              * count it as precision.
  681.              */
  682.             --prec;
  683.             fmtch -= 2;        /* G->E, g->e */
  684.             gformat = 1;
  685.             goto eformat;
  686.         }
  687.         /*
  688.          * reverse integer into beginning of buffer,
  689.          * note, decrement precision
  690.          */
  691.         if (expcnt)
  692.             for (; ++p < endp; *t++ = *p, --prec);
  693.         else
  694.             *t++ = '0';
  695.         /*
  696.          * if precision required or alternate flag set, add in a
  697.          * decimal point.  If no digits yet, add in leading 0.
  698.          */
  699.         if (prec || flags&ALT) {
  700.             dotrim = 1;
  701.             *t++ = decimal;
  702.         }
  703.         else
  704.             dotrim = 0;
  705.         /* if requires more precision and some fraction left */
  706.         while (prec && fract) {
  707.             fract = modfl(fract * 10.0L, &tmp);
  708.             *t++ = tochar((int)tmp);
  709.             prec--;
  710.         }
  711.         if (fract)
  712.             startp = roundl(fract, (int *)NULL, startp, t - 1,
  713.                     (char)0, signp);
  714.         /* alternate format, adds 0's for precision, else trim 0's */
  715.         if (flags&ALT)
  716.             for (; prec--; *t++ = '0');
  717.         else if (dotrim) {
  718.             while (t > startp && *--t == '0');
  719.             if (*t != decimal)
  720.                 ++t;
  721.         }
  722.     }
  723.     return(t - startp);
  724. }
  725.  
  726. static char *
  727. roundl(long double fract, int *exp, char *start, char *end, char ch,
  728.        char *signp)
  729. {
  730.     long double tmp;
  731.  
  732.     if (fract)
  733.     {
  734.         if (fract == 0.5L)
  735.         {
  736.             char *e = end;
  737.             if (*e == '.')
  738.             e--;
  739.             if (*e == '0' || *e == '2' || *e == '4'
  740.             || *e == '6' || *e == '8')
  741.             {
  742.             tmp = 3.0;
  743.             goto start;
  744.             }
  745.         }
  746.         (void)modfl(fract * 10.0L, &tmp);
  747.     }
  748.     else
  749.         tmp = todigit(ch);
  750. start:
  751.     if (tmp > 4)
  752.         for (;; --end) {
  753.             if (*end == decimal)
  754.                 --end;
  755.             if (++*end <= '9')
  756.                 break;
  757.             *end = '0';
  758.             if (end == start) {
  759.                 if (exp) {    /* e/E; increment exponent */
  760.                     *end = '1';
  761.                     ++*exp;
  762.                 }
  763.                 else {        /* f; add extra digit */
  764.                     *--end = '1';
  765.                     --start;
  766.                 }
  767.                 break;
  768.             }
  769.         }
  770.     /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
  771.     else if (*signp == '-')
  772.         for (;; --end) {
  773.             if (*end == decimal)
  774.                 --end;
  775.             if (*end != '0')
  776.                 break;
  777.             if (end == start)
  778.                 *signp = 0;
  779.         }
  780.     return(start);
  781. }
  782.  
  783. static char *
  784. exponentl(char *p, int exp, u_char fmtch)
  785. {
  786.     register char *t;
  787.     char expbuf[MAXEXPLD];
  788.  
  789.     *p++ = fmtch;
  790.     if (exp < 0) {
  791.         exp = -exp;
  792.         *p++ = '-';
  793.     }
  794.     else
  795.         *p++ = '+';
  796.     t = expbuf + MAXEXPLD;
  797.     if (exp > 9) {
  798.         do {
  799.             *--t = tochar(exp % 10);
  800.         } while ((exp /= 10) > 9);
  801.         *--t = tochar(exp);
  802.         for (; t < expbuf + MAXEXPLD; *p++ = *t++);
  803.     }
  804.     else {
  805.         *p++ = '0';
  806.         *p++ = tochar(exp);
  807.     }
  808.     return(p);
  809. }
  810.  
  811. #ifdef hp300
  812. isspecial(d, bufp, signp)
  813.     double d;
  814.     char *bufp, *signp;
  815. {
  816.     register struct IEEEdp {
  817.         unsigned sign:1;
  818.         unsigned exp:11;
  819.         unsigned manh:20;
  820.         unsigned manl:32;
  821.     } *ip = (struct IEEEdp *)&d;
  822.  
  823.     if (ip->exp != 0x7ff)
  824.         return(0);
  825.     if (ip->manh || ip->manl)
  826.         (void)strcpy(bufp, "NaN");
  827.     else
  828.         (void)strcpy(bufp, "Inf");
  829.     return(3);
  830. }
  831. #endif
  832.  
  833. #ifdef __GO32__
  834. static int
  835. isspeciall(long double d, char *bufp)
  836. {
  837.     register struct IEEExp {
  838.             unsigned manl:32;
  839.         unsigned manh:32;
  840.         unsigned exp:15;
  841.             unsigned sign:1;
  842.     } *ip = (struct IEEExp *)&d;
  843.  
  844.     if (ip->exp != 0x7fff)
  845.         return(0);
  846.     if ((ip->manh & 0x7fffffff) || ip->manl)
  847.         {
  848.         strcpy(bufp, "NaN");
  849.             nan = 1; /* kludge: we don't need the sign,  it's not nice
  850.                     but it should work */
  851.         }
  852.     else
  853.         (void)strcpy(bufp, "Inf");
  854.         return(3);
  855. }
  856. #endif
  857.  
  858.